import { MqttClient, connect } from 'mqtt';
import { QXEvent, isArray } from 'qx-util';
import { acc } from '@ibizstudio/api';

/**
 * ws服务
 *
 * @author chitanda
 * @date 2021-06-15 10:06:02
 * @export
 * @class WSService
 */
export class WSService {
  protected static instance = new WSService();
  readonly evt: QXEvent<{ message: any }> = new QXEvent();
  /**
   * 连接选项
   *
   * @protected
   * @memberof WSService
   */
  protected options = {
    // 超时时间
    connectTimeout: 4000,
    // 认证信息
    clientId: '',
    // username: 'emqx',
    // password: 'emqx',
    // 心跳时间
    keepalive: 60,
    clean: true,
  };
  /**
   * 链接实例
   *
   * @protected
   * @type {MqttClient}
   * @memberof WSService
   */
  protected ws!: MqttClient;
  /**
   * 连接地址
   *
   * @protected
   * @type {string}
   * @memberof WSService
   */
  protected url?: string;
  /**
   * 订阅标识
   *
   * @author chitanda
   * @date 2021-06-15 11:06:14
   * @protected
   * @type {string}
   */
  protected id: string | string[] = '';
  /**
   * Creates an instance of WSService.
   *
   * @author chitanda
   * @date 2021-06-15 10:06:46
   */
  constructor() {
    if (WSService.instance) {
      return WSService.instance;
    }
  }

  /**
   * 初始化
   *
   * @author chitanda
   * @date 2021-06-15 11:06:03
   * @param {string} url
   * @param {string} id
   * @param {*} [opt]
   */
  init(url: string, id: string | string[], opt?: any): void {
    this.url = url;
    this.id = id;
    this.options.clientId = `ws-${id}-${new Date().getTime()}`;
    if (opt) {
      Object.assign(this.options, opt);
    }
    this.initEvents();
  }

  /**
   * 初始化事件订阅
   *
   * @author chitanda
   * @date 2021-06-15 11:06:14
   * @protected
   */
  protected initEvents(): void {
    if(this.ws){
      this.ws.end(true)
      this.ws.removeAllListeners()
    }
    this.ws = connect(this.url, this.options);
    this.connect();
    this.reconnect();
    this.error();
    this.message();
  }

  /**
   * 启用websocket连接
   *
   * @author chitanda
   * @date 2021-06-15 11:06:28
   * @protected
   */
  protected connect(): void {
    this.ws.on('connect', () => {
      if (isArray(this.id)) {
        (this.id as string[]).forEach(tag => {
          this.ws.subscribe(tag, { qos: 1 }, (err: any) => {
            if (err) {
              console.error('Central 订阅失败', err);
              return;
            }
          });
        });
      } else {
        this.ws.subscribe(this.id, { qos: 1 }, (err: any) => {
          if (err) {
            console.error('Central 订阅失败', err);
            return;
          }
        });
      }
    });
  }

  /**
   * 重新链接
   *
   * @author chitanda
   * @date 2021-06-15 11:06:04
   * @protected
   */
  protected reconnect(): void {
    this.ws.on('reconnect', (error: any) => {
      if (!error) {
        console.log('正在重连...');
      } else {
        console.warn('重连失败:', error);
      }
    });
  }

  /**
   * 异常处理
   *
   * @author chitanda
   * @date 2021-06-15 11:06:40
   * @protected
   */
  protected error(): void {
    this.ws.on('error', (error: any) => {
      console.log('连接失败:', error);
    });
  }

  /**
   * 订阅消息
   *
   * @author chitanda
   * @date 2021-06-15 11:06:10
   * @protected
   */
  protected message(): void {
    this.ws.on('message', (topic: any, message: any) => {
      let ms: string = '';
      try {
        if (isArray(this.id)) {
          if (this.id.indexOf(topic) !== -1) {
            ms = message.toString('utf-8');
            const data: any = JSON.parse(ms);
            acc.system.next(data);
          }
        } else {
          if (topic === this.id) {
          }
        }
      } catch (error) {
        console.warn('消息中心：websocket消息解析失败!');
        console.warn('消息内容：', ms);
        console.error(error);
      }
    });
  }

  /**
   * 获取唯一实例
   *
   * @author chitanda
   * @date 2021-06-15 10:06:48
   * @static
   * @return {*}  {WSService}
   */
  static getInstance(): WSService {
    return this.instance;
  }
}
// 导出默认实例
export const ws = new WSService();
